package helper

import (
	"crypto/md5" // 导入MD5加密包
	"crypto/tls"
	"fmt" // 导入格式化包
	"github.com/dgrijalva/jwt-go"
	"github.com/jordan-wright/email"
	uuid "github.com/satori/go.uuid"
	"math/rand"
	"net/smtp"
	"os"
	"strconv"
	"time"
)

// GetMd5 计算字符串的MD5哈希值
func GetMd5(s string) string {
	// 将输入字符串转换为字节切片，计算MD5哈希，并格式化为十六进制字符串
	return fmt.Sprintf("%x", md5.Sum([]byte(s)))
}

// UserClaims 自定义JWT声明结构体
type UserClaims struct {
	Identity           string `json:"identity"` // 用户身份标识
	Name               string `json:"name"`     // 用户名
	IsAdmin            int    `json:"is_admin"`
	jwt.StandardClaims        // 嵌入JWT标准声明
}

// JWT签名密钥（用于token签名和验证）
var myKey = []byte("gin-gorm-oj-key")

// GenerateToken 生成token
func GenerateToken(identity, name string, isAdmin int) (string, error) {
	// 创建用户声明信息
	UserClaim := &UserClaims{
		Identity:       identity, // 用户唯一标识
		Name:           name,     // 用户名
		IsAdmin:        isAdmin,
		StandardClaims: jwt.StandardClaims{}, // JWT标准声明（过期时间等）
	}

	// 使用HS256算法和用户声明创建token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, UserClaim)
	// 使用密钥对token进行签名，生成token字符串
	tokenString, err := token.SignedString(myKey)

	// 错误处理：签名失败时终止测试
	if err != nil {
		return "", err
	}
	return tokenString, nil
}

// AnalyseToken 解析 token
func AnalyseToken(token string) (*UserClaims, error) {
	// 创建UserClaims实例，用于存储解析后的token数据
	userClaim := new(UserClaims)

	// 解析JWT token并验证签名
	claims, err := jwt.ParseWithClaims(token, userClaim, func(token *jwt.Token) (interface{}, error) {
		return myKey, nil // 返回签名密钥进行验证
	})

	// 解析错误处理
	if err != nil {
		return nil, err // 返回错误信息
	}

	// 验证token是否有效
	if !claims.Valid {
		// 如果token无效，返回nil和格式化错误信息
		return nil, fmt.Errorf("analyse Token Error:%v", err)
	}

	// 返回解析后的用户声明
	return userClaim, nil
}

// SendCode 发送邮件验证码
// toUserEmail: 收件人邮箱地址
// code: 要发送的验证码
func SendCode(toUserEmail, code string) error {

	e := email.NewEmail()              // 创建邮件对象
	e.From = "发件人 <sloan1993@163.com>" // 设置发件人信息
	e.To = []string{toUserEmail}       // 设置收件人邮箱
	e.Subject = "验证码发送"                // 设置邮件主题
	// 设置HTML格式的邮件内容，包含验证码
	e.HTML = []byte("您的验证码：<b>" + code + "</b>")

	// 使用TLS加密方式发送邮件
	return e.SendWithTLS(
		"smtp.163.com:465", // SMTP服务器地址和端口
		smtp.PlainAuth(
			"",                  // 身份标识（通常为空）
			"sloan1993@163.com", // 发件人邮箱账号
			"XYQHBVISUAHXXRQ",   // SMTP授权密码
			"smtp.163.com",      // SMTP服务器地址
		),
		&tls.Config{
			InsecureSkipVerify: true,           // 跳过证书验证（生产环境不建议）
			ServerName:         "smtp.163.com", // 服务器名称
		},
	)
}

// GetUUID 生成全局唯一标识符
func GetUUID() string {
	// 使用UUID v4版本生成随机唯一标识符并返回字符串格式
	return uuid.NewV4().String()
}

// GetRand 生成6位数字验证码
// 生成验证码
func GetRand() string {
	rand.Seed(time.Now().UnixNano()) // 设置随机数种子，基于当前时间
	s := ""                          // 初始化空字符串
	for i := 0; i < 6; i++ {         // 循环6次，生成6位验证码
		s += strconv.Itoa(rand.Intn(10)) // 生成0-9随机数并转为字符串
	}
	return s // 返回6位数字验证码
}

// CodeSave 保存用户代码到文件
func CodeSave(code []byte) (string, error) {
	// 生成唯一目录路径：code/ + UUID
	dirName := "code/" + GetUUID()
	// 构建完整文件路径：目录/main.go
	path := dirName + "/main.go"

	// 创建代码目录（权限0777：所有者、组、其他用户可读可写可执行）
	err := os.Mkdir(dirName, 0777)
	if err != nil {
		return "", err // 目录创建失败，返回错误
	}

	// 创建代码文件
	f, err := os.Create(path)
	if err != nil {
		return "", err // 文件创建失败，返回错误
	}

	f.Write(code)    // 写入代码内容到文件
	defer f.Close()  // 延迟关闭文件（函数返回时自动执行）
	return path, nil // 操作成功
}
